home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 4
/
Apprentice-Release4.iso
/
Source Code
/
Libraries
/
Graphic Elements 3
/
GESound
/
GESound.c
< prev
next >
Wrap
Text File
|
1995-08-24
|
9KB
|
322 lines
/*
GESound.c
Asynch sound player for use with Graphic Elements
Requires Sound Manager 3.0 or later
Copyright 1995 by Al Evans. All rights reserved.
3/10/95
*/
#include "GESound.h"
typedef struct geSEntry *GESoundLEntryPtr;
typedef struct geSEntry {
GESoundLEntryPtr nextEntry;
short resID;
short nUsers;
long flags; // Keep in memory, etc.
Handle sound;
} GESoundListEntry;
static pascal void SndDoneProc(SndChannelPtr channel, SndCommand *cmd);
GESoundPtr GEInitSounds(short nSoundChannels)
{
GESoundPtr sound;
long size = sizeof(LHeaderPtr) + sizeof(long) +
(2 * sizeof(short)) + (nSoundChannels * sizeof(GESndChan));
short sndCount;
OSErr err;
if (SndSoundManagerVersion().majorRev < 3)
return nil;
sound = (GESoundPtr) NewPtrClear(size);
if (sound == nil)
return nil;
sound->soundsLoaded = InitList(20, sizeof(GESoundListEntry));
if (sound->soundsLoaded == nil)
return nil;
sound->soundCallBack = NewSndCallBackProc(SndDoneProc);
sound->nCurrent = 0;
sound->soundEnabled = 1;
for (sndCount = 0; sndCount < nSoundChannels; sndCount++)
{
err = SndNewChannel(&sound->soundChannel[sndCount].channel,
sampledSynth, initMono, sound->soundCallBack);
if (err != noErr)
break;
sound->soundChannel[sndCount].priority = -1;
sound->soundChannel[sndCount].sndNum = 0;
sound->nChannels++; // Only count the ones that actually get created!
}
if (sound->nChannels == 0)
goto abort;
return sound;
abort:
if (sound != nil) {
if (sound->soundsLoaded != nil)
DeleteList(sound->soundsLoaded);
for (sndCount = 0; sndCount < sound->nChannels; sndCount++) {
if (sound->soundChannel[sndCount].channel != nil)
SndDisposeChannel(sound->soundChannel[sndCount].channel, true);
}
DisposePtr((Ptr) sound);
}
return nil;
}
Boolean SndCompare(Ptr snd1, Ptr snd2)
{
return (((GESoundLEntryPtr) snd2)->resID > ((GESoundLEntryPtr) snd1)->resID );
}
GESoundLEntryPtr GEGetSoundsRec(GESoundPtr sounds, short sndResID)
{
GESoundLEntryPtr thisSnd = (GESoundLEntryPtr) sounds->soundsLoaded->listHead;
while (thisSnd != nil) {
if (thisSnd->resID == sndResID)
break;
thisSnd = (GESoundLEntryPtr) thisSnd->nextEntry;
}
return thisSnd;
}
GESoundLEntryPtr GELoadSound(GESoundPtr sounds, short sndResID)
{
Handle sndHandle = nil;
GESoundLEntryPtr thisSnd = GEGetSoundsRec(sounds, sndResID);
if (thisSnd == nil) {
// Need to load (& lock??) it
sndHandle = (Handle) GetResource('snd ', sndResID);
if (sndHandle == nil)
return nil;
MoveHHi(sndHandle);
HLock(sndHandle);
thisSnd = (GESoundLEntryPtr) AllocateEntry(sounds->soundsLoaded);
thisSnd->resID = sndResID;
thisSnd->nUsers = 0;
thisSnd->flags = 0;
thisSnd->sound = sndHandle;
InsertEntry(sounds->soundsLoaded, (LMemberPtr) thisSnd, SndCompare);
}
return thisSnd;
}
void GEReleaseChannel(GESoundPtr sounds, short chanIndex);
GESndChanPtr GEAllocChannel(GESoundPtr sounds, short priority)
{
GESndChanPtr channel = nil;
short chanCt;
OSErr err;
// Find an unused channel
for (chanCt = 0; chanCt < sounds->nChannels; chanCt++) {
if (sounds->soundChannel[chanCt].priority == -1) {
if (sounds->soundChannel[chanCt].sndNum != 0)
GEReleaseChannel(sounds, chanCt);
channel = &sounds->soundChannel[chanCt];
break;
}
}
// Find channel with priority < new priority and stop sound
if (channel == nil) {
for (chanCt = 0; chanCt < sounds->nChannels; chanCt++) {
if (priority >= sounds->soundChannel[chanCt].priority) {
GEStopOneSound(sounds, sounds->soundChannel[chanCt].sndNum);
GEReleaseChannel(sounds, chanCt);
channel = &sounds->soundChannel[chanCt];
break;
}
}
}
return channel;
}
void GEHoldSound(GESoundPtr sounds, short sndResID, Boolean keepInMemory)
{
if (keepInMemory) {
GESoundLEntryPtr thisSnd = GELoadSound(sounds, sndResID);
if (thisSnd != nil)
thisSnd->flags |= 1;
}
else {
GESoundLEntryPtr thisSnd = GEGetSoundsRec(sounds, sndResID);
if (thisSnd != nil)
thisSnd->flags &= ~1;
}
}
OSErr GEScheduleSound(GESoundPtr sounds, short sndResID, short priority,
unsigned long msDelay)
{
// If sound not in memory, load it
GESoundLEntryPtr thisSnd = GELoadSound(sounds, sndResID);
GESndChanPtr channel = nil;
OSErr err = noErr;
if (thisSnd == nil)
return ResError(); // ??
channel = GEAllocChannel(sounds, priority);
if (channel == nil)
return badChannel;
sounds->nCurrent += 1;
// thisSnd->flags |= keepInMemory; // ??
thisSnd->nUsers += 1;
channel->playTime = TickCount() + (msDelay/16);
channel->priority = priority;
channel->sndNum = sndResID;
return noErr;
}
void GEnableSound(GESoundPtr sounds, Boolean enableIt)
{
sounds->soundEnabled = enableIt;
if ((!enableIt) && (sounds->nCurrent > 0))
GEStopAllSounds(sounds);
}
void GEReleaseChannel(GESoundPtr sounds, short chanIndex)
{
GESndChanPtr channel = &sounds->soundChannel[chanIndex];
GESoundLEntryPtr thisSnd = GEGetSoundsRec(sounds, channel->sndNum);
if (thisSnd == nil)
return;
thisSnd->nUsers -= 1;
if ((thisSnd->nUsers == 0) && ((thisSnd->flags & 1) == 0)) {
ReleaseResource(thisSnd->sound);
DeleteEntry(sounds->soundsLoaded, (LMemberPtr) thisSnd);
}
channel->sndNum = 0;
sounds->nCurrent -= 1;
}
void GEPlaySndNow(GESoundPtr sounds, GESndChanPtr chan)
{
GESoundLEntryPtr thisSnd = GEGetSoundsRec(sounds, chan->sndNum);
OSErr err = noErr;
if (thisSnd == nil)
return;
err = SndPlay(chan->channel, (SndListHandle) thisSnd->sound, true );
if (err == noErr) {
SndCommand cmd;
cmd.cmd = callBackCmd;
cmd.param2 = (long) chan;
err = SndDoCommand(chan->channel, &cmd, false);
}
}
void GESoundMaintenance(GESoundPtr sounds)
{
unsigned long currTime = TickCount();
short chanCt;
// Dispose used sounds, start those that need to play now
for (chanCt = 0; chanCt < sounds->nChannels; chanCt++) {
if ((sounds->soundChannel[chanCt].sndNum != 0) && // Has a sound &&
(sounds->soundChannel[chanCt].priority == -1)) { // Finished playing
GEReleaseChannel(sounds, chanCt);
}
else {
unsigned long playTime = sounds->soundChannel[chanCt].playTime;
if ((playTime != 0) && (currTime >= playTime)) {
if (sounds->soundEnabled) // Start sound...
GEPlaySndNow(sounds, &sounds->soundChannel[chanCt]);
else // Allow it to be unloaded
sounds->soundChannel[chanCt].priority = -1;
sounds->soundChannel[chanCt].playTime = 0;
}
}
}
}
Boolean GESoundPlaying(GESoundPtr sounds, short sndResID)
{
short chanCt;
for (chanCt = 0; chanCt < sounds->nChannels; chanCt++) {
if (sounds->soundChannel[chanCt].sndNum == sndResID) {
return (sounds->soundChannel[chanCt].priority != -1);
}
}
return false;
}
void GEStopOneSound(GESoundPtr sounds, short sndResID)
{
short chanCt;
for (chanCt = 0; chanCt < sounds->nChannels; chanCt++) {
if (sounds->soundChannel[chanCt].sndNum == sndResID) {
SndCommand cmd;
OSErr err;
cmd.cmd = quietCmd;
cmd.param1 = 0;
cmd.param2 = 0;
err = SndDoImmediate( sounds->soundChannel[chanCt].channel, &cmd );
cmd.cmd = flushCmd;
err = SndDoImmediate( sounds->soundChannel[chanCt].channel, &cmd );
sounds->soundChannel[chanCt].priority = -1;
return;
}
}
}
void GEStopAllSounds(GESoundPtr sounds)
{
short chanCt;
for (chanCt = 0; chanCt < sounds->nChannels; chanCt++) {
if (sounds->soundChannel[chanCt].priority != -1) {
SndCommand cmd;
OSErr err;
cmd.cmd = quietCmd;
cmd.param1 = 0;
cmd.param2 = 0;
err = SndDoImmediate( sounds->soundChannel[chanCt].channel, &cmd );
cmd.cmd = flushCmd;
err = SndDoImmediate( sounds->soundChannel[chanCt].channel, &cmd );
sounds->soundChannel[chanCt].priority = -1;
return;
}
}
GESoundMaintenance(sounds);
}
void GEDisposeSounds(GESoundPtr sounds)
{
GESoundLEntryPtr thisSnd = (GESoundLEntryPtr) sounds->soundsLoaded->listHead;
short sndCount;
GEStopAllSounds(sounds);
while (thisSnd != nil) {
if (thisSnd->sound != nil)
ReleaseResource(thisSnd->sound);
thisSnd = (GESoundLEntryPtr) thisSnd->nextEntry;
}
DeleteList(sounds->soundsLoaded);
DisposeRoutineDescriptor((UniversalProcPtr) sounds->soundCallBack);
for (sndCount = 0; sndCount < sounds->nChannels; sndCount++) {
if (sounds->soundChannel[sndCount].channel != nil)
SndDisposeChannel(sounds->soundChannel[sndCount].channel, true);
}
DisposePtr((Ptr) sounds);
}
static pascal void SndDoneProc(SndChannelPtr channel, SndCommand *cmd)
{
GESndChanPtr geChannel = (GESndChanPtr) cmd->param2;
geChannel->priority = -1;
}